package com.tbox.tbsdk;

import android.text.TextUtils;
import android.util.Log;

import com.lib.util.SPUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;

/**
 * Created by rui.yang
 * on 2020/12/3
 */
class FramePackage {
    private static byte serialNumber = 0x01;

    /// 流水号，自动累加
    private static byte getSerialNumber() {
        if (serialNumber == 127) {
            return serialNumber = 0x01;
        }
        return serialNumber ++;
    }

    /// 鉴权帧
    public static byte[] packageIdentificationFrame() {
        /// 帧内容
        Calendar CD = Calendar.getInstance();
        int YY = CD.get(Calendar.YEAR) ;
        int MM = CD.get(Calendar.MONTH)+1;
        int DD = CD.get(Calendar.DATE);
        int HH = CD.get(Calendar.HOUR);
        int NN = CD.get(Calendar.MINUTE);
        int SS = CD.get(Calendar.SECOND);

        /// 时间
        byte[] time = new byte[] {
                (byte) (YY % 100),
                (byte) MM,
                (byte) DD,
                (byte) HH,
                (byte) NN,
                (byte) SS,
        };

        /// 直接转换字符串，字符串为乱码
        String timeString = new String(time);

        String TBoxSecretKey = SPUtils.getInstance().getString(Constant.KEY_TBOX);
        Log.e("lanbin","TBoxSecretKey=  "+TBoxSecretKey);
        /// tbox key md5，转换为可读16进制字符串
        byte[] token = HexUtil.hexStringToBytes(md5(TBoxSecretKey));
        String tokenString = HexUtil.bytesToHexString(token);

        /// 拼接后 AES128 加密
        String beforeAES128String = timeString + tokenString;
        Log.e("before aes128", beforeAES128String);
        String AES128SecretKey = SPUtils.getInstance().getString(Constant.KEY_AES);
        Log.e("lanbin","AES128SecretKey=  "+AES128SecretKey);

        byte[] afterAES128Bytes = AesUtil.encryptUTF8String(beforeAES128String, AES128SecretKey);
        String afterAES128String = HexUtil.bytesToHexString(afterAES128Bytes);
        Log.e("after aes128", afterAES128String);

        byte[] frame = ByteUtil.merge(
                FramePackage.getHeaderBytes((byte) 0x01, (byte)0xfe),
                afterAES128Bytes,
                FramePackage.getFooterBytes());

        /// 校正长度与 bcc 校验位
        frame = correctionFrame(frame);
        return frame;
    }

    /// 心跳帧
    public static byte[] packageHeartbeatFrame() {
        byte[] frame = ByteUtil.merge(
                FramePackage.getHeaderBytes((byte) 0x04, (byte)0xfe, (byte) 0x00, getSerialNumber()),
                FramePackage.getFooterBytes());

        /// 校正长度与 bcc 校验位
        frame = correctionFrame(frame);
        return frame;
    }

    /// 确认帧
    public static byte[] packageAckFrame(byte serialNumber) {
        byte[] frame = ByteUtil.merge(
                FramePackage.getHeaderBytes((byte) 0x00, (byte)0x00, (byte) 0x00, serialNumber),
                FramePackage.getFooterBytes());

        /// 校正长度与 bcc 校验位
        frame = correctionFrame(frame);
        return frame;
    }

    /// 状态同步确认
    public static byte[] packageStatusSyncAck(byte serialNumber, byte status) {
        String AES128SecretKey = SPUtils.getInstance().getString(Constant.KEY_AES);

        /// 帧内容
        byte[] afterAES128Bytes = AesUtil.encrypt(new byte[]{status}, AES128SecretKey);

        byte[] frame = ByteUtil.merge(
                FramePackage.getHeaderBytes((byte) 0x03, (byte)0xfe, (byte)0x02, serialNumber),
                afterAES128Bytes,
                FramePackage.getFooterBytes());

        /// 校正长度与 bcc 校验位
        frame = correctionFrame(frame);
        return frame;
    }

    /// 解锁车辆
    public static byte[] packageUnlockFrame() {
        return packageCarControlFrame((byte) 0x01);
    }

    /// 上锁车辆
    public static byte[] packageLockFrame() {
        return packageCarControlFrame((byte) 0x02);
    }

    /// 寻车
    public static byte[] packageLookForFrame() {
        return packageCarControlFrame((byte) 0x03);
    }


    /// 车辆上电
    public static byte[] packagePowerOnFrame() {
        return packageCarControlFrame((byte) 0x04);
    }

    /// 车辆下电
    public static byte[] packagePowerOffFrame() {
        return packageCarControlFrame((byte) 0x05);
    }


    /// 车辆控制
    private static byte[] packageCarControlFrame(byte control) {
        /// 帧内容
        Calendar CD = Calendar.getInstance();
        int YY = CD.get(Calendar.YEAR) ;
        int MM = CD.get(Calendar.MONTH)+1;
        int DD = CD.get(Calendar.DATE);
        int HH = CD.get(Calendar.HOUR);
        int NN = CD.get(Calendar.MINUTE);
        int SS = CD.get(Calendar.SECOND);

        /// 帧组装
        byte[] content = new byte[] {
                (byte) (YY % 100),
                (byte) MM,
                (byte) DD,
                (byte) HH,
                (byte) NN,
                (byte) SS,
                control,
        };
        String AES128SecretKey = SPUtils.getInstance().getString(Constant.KEY_AES);
        byte[] afterAES128Bytes = AesUtil.encrypt(content, AES128SecretKey);
        byte[] frame = ByteUtil.merge(
                FramePackage.getHeaderBytes((byte) 0x02, (byte)0xfe),
                afterAES128Bytes,
                FramePackage.getFooterBytes());

        /// 校正长度与 bcc 校验位
        frame = correctionFrame(frame);
        return frame;
    }

    private static byte[] correctionFrame(byte[] frame) {
        /// 校正帧长度
        frame[2] = (byte)frame.length;

        /// 校正 bcc
        frame[frame.length - 3] = ByteUtil.bcc(frame, 0, frame.length - 3);
        return frame;
    }

    /// 获取帧头
    public static byte[] getHeaderBytes(byte cmd1, byte cmd2) {
        return getHeaderBytes(cmd1, cmd2, (byte)0x02 /** AES128 */, getSerialNumber());
    }
    public static byte[] getHeaderBytes(byte cmd1, byte cmd2, byte crypto, byte serialNumber) {
        return new byte[]{
                0x55,
                0x55, /** 固定帧头描述 */
                0x00, /** 长度，待校正 */
                crypto, /**  加密：0x00 - 不加密，0x01 – DES3，0x02 – AES128 */
                serialNumber,  /** 流水号 */
                cmd1, /** 指令，两个字节 */
                cmd2,
        };
    }

    /// 获取帧尾
    public static byte[] getFooterBytes() {
        return new byte[]{
                0x00,  /** bcc 校验位，待校正 */
                (byte) (0xaa),
                (byte) (0xaa), /** 固定帧尾描述 */
        };
    }

    /// MD5 计算
    public static String md5(String string) {
        if (TextUtils.isEmpty(string)) {
            return "";
        }
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(string.getBytes());
            String result = "";
            for (byte b : bytes) {
                String temp = Integer.toHexString(b & 0xff);
                if (temp.length() == 1) {
                    temp = "0" + temp;
                }
                result += temp;
            }
            return result;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }
}
